/*
 * Copyright (C) 2010-2011 Comcast Cable.  All Rights Reserved.
 */
package com.hercules.android.receiver.connection.parser.json.itemparsers;

import com.google.gjson.JSONArray;
import com.google.gjson.JSONException;
import com.google.gjson.JSONObject;
import com.hercules.android.receiver.connection.parser.CommandParsingException;
import com.hercules.android.receiver.connection.parser.MalformedCommandException;

import java.lang.reflect.Array;

/**
 * Parser for array properties.
 * <p>
 * AndroidAssembly3 this class was added in Android Assembly 3.
 *
 * @author TCSASSEMBLER
 * @version 1.0
 */
public class ArrayParser extends FieldParser {
    /** Represents the expected length of array property. */
    private final int arrayLength;
    /** Represents the expected item class of array property. */
    private final Class<?> itemClass;

    /**
     * Constructor for class ArrayParser.
     *
     * @param isRequired indicates if property is required
     * @param itemClass the expected item class
     * @param arrayLength the expected length of array
     */
    public ArrayParser(boolean isRequired, Class<?> itemClass, int arrayLength) {
        super(isRequired);
        this.itemClass = itemClass;
        this.arrayLength = arrayLength;
    }

    /**
     * Gets the expected length of array property.
     *
     * @return the expected length of array property
     */
    public int getArrayLength() {
        return arrayLength;
    }

    /**
     * Parses array property.
     *
     * @param path the path to value
     * @param json the JSON
     * @param keyName the name of current JSON key
     * @param instance the instance of object, parsed value will be set to it
     * @return the parsed value
     * @throws CommandParsingException if error occurs while parsing
     */
    @SuppressWarnings("boxing")
    @Override
    protected Object doParse(StringBuilder path, JSONObject json, String keyName, Object instance)
        throws CommandParsingException {
        try {
            JSONArray jsonArray = json.get(keyName).isArray();

            if (jsonArray == null || jsonArray.isNull() != null) {
            	return null;
            }
            
            // check length of array
            if (jsonArray.size() != arrayLength) {
                throw new MalformedCommandException("The array length for '" + keyName + "' should be " + arrayLength
                    + ".");
            }

            // create array instance
            Object array = Array.newInstance(itemClass, arrayLength);

            // assign values to array items
            boolean expressionExpected = false;
            for (int i = 0; i < arrayLength; i++) {
                if (int.class.equals(itemClass)) {
                    // special workaround for 'dimension', they should be converted from double to int
                	if (jsonArray.get(i).isNumber() == null) {
                		expressionExpected = true;
                		break;
                	}
                    Array.set(array, i, (int) jsonArray.get(i).isNumber().doubleValue());
                } else if (double.class.equals(itemClass)) {
                	if (jsonArray.get(i).isNumber() == null) {
                		expressionExpected = true;
                		break;
                	}
                    Array.set(array, i, jsonArray.get(i).isNumber().doubleValue());
                } else {
                    Array.set(array, i, jsonArray.get(i).isString().stringValue());
                }
            }
            
            if (!expressionExpected) {
            	return array;
            }
            
            String[] result = new String[arrayLength];
            for (int i = 0; i < arrayLength; i++) {
            	if (jsonArray.get(i).isString() != null) {
            		result[i] = jsonArray.get(i).isString().stringValue();
            	} else {
            		result[i] = "{" + jsonArray.get(i).isNumber().doubleValue() + "}";
            	}
            }
            return result;
        } catch (IllegalArgumentException e) {
            throw new MalformedCommandException("Incorrect array type for '" + keyName + "' at JSON '" + json
                + "', expected item class " + itemClass.getName() + ".", e);
        } catch (JSONException e) {
            throw new MalformedCommandException("Failed to process array '" + keyName + "' property at JSON '" + json
                + "'.", e);
        }
    }
}
